/**
* 光源计算
* @param pos 世界坐标系下的坐标
* @return 光源方向向量,强度系数
*/
#pragma DECLARE_BEGIN(common_light, FRAGMENT)
uniform vec4 uLightPos;
uniform vec4 uLightDir;
uniform vec4 uLightColor;
vec4 common_light(vec3 pos)
{
	float intensity = 1.0;
	vec3 lightDir = -uLightDir.xyz;
	if (uLightPos.w != 0.0)
	{
		vec3 direction = uLightPos.xyz - pos;
		intensity = max(1.0 - length(direction) / uLightColor.a, 0.0);
		lightDir = normalize(direction);
		if (uLightDir.w > 0.0)
		{
			float spotFactor = dot(lightDir, -uLightDir.xyz);
			intensity *= max(spotFactor - uLightDir.w, 0.0) / (1.0 - uLightDir.w);
		}
	}
	return vec4(lightDir, intensity * intensity);
}
#pragma DECLARE_END

/**
* 光源及阴影计算
* @param pos 世界坐标系下的坐标
* @param coord 当前像素阴影贴图坐标系坐标
* @return 光源方向向量,强度系数
*/
#pragma DECLARE_BEGIN(common_lightshadow, FRAGMENT, ENABLE_SHADOW)
#define SHADOWMAP_PCF_TAP_COUNT 32
uniform vec4 uLightPos;
uniform vec4 uLightDir;
uniform vec4 uLightColor;
uniform float uLightSize;
uniform vec2 uLightSizeCorrection[4];
uniform vec4 uCascadeFarPlane;
uniform sampler2D uShadowMap;
uniform samplerCube uShadowMapCube;
uniform sampler2DArray uShadowMapArray;
const vec2 poissonDisk[32] = vec2[32](
	vec2( 0.0640701,  0.0540992),
	vec2( 0.7366577,  0.5789394),
	vec2(-0.6270542, -0.5320278),
	vec2(-0.4096107,  0.8411095),
	vec2( 0.6849564, -0.4990818),
	vec2(-0.8741811, -0.0457973),
	vec2( 0.9989998,  0.0009880),
	vec2(-0.0049206, -0.9151649),
	vec2( 0.1805763,  0.9747483),
	vec2(-0.2138451,  0.2635818),
	vec2( 0.1098451,  0.3884785),
	vec2( 0.0687675, -0.3581074),
	vec2( 0.3740731, -0.7661266),
	vec2( 0.3079132, -0.1216763),
	vec2(-0.3794335, -0.8271583),
	vec2(-0.2038781, -0.0771503),
	vec2( 0.5912697,  0.1469799),
	vec2(-0.8806902,  0.3031784),
	vec2( 0.5040108,  0.8283722),
	vec2(-0.5844124,  0.5494877),
	vec2( 0.6017799, -0.1726654),
	vec2(-0.5554981,  0.1559997),
	vec2(-0.3016369, -0.3900928),
	vec2(-0.5550632, -0.1723762),
	vec2( 0.9250291,  0.2995041),
	vec2(-0.2473137,  0.5538505),
	vec2( 0.9183037, -0.2862392),
	vec2( 0.2469421,  0.6718712),
	vec2( 0.3916397, -0.4328209),
	vec2(-0.0357692, -0.6220032),
	vec2(-0.0466125,  0.7995201),
	vec2( 0.4402924,  0.3640312)
);
float shadow_spotlight_pcf(vec3 coord)
{
	float result = 0.0;
	for (int i = 0; i < SHADOWMAP_PCF_TAP_COUNT; i++)
	{
		float compare = texture(uShadowMap, coord.xy + poissonDisk[i] * uLightSize).r;
		result += step(0.0, compare - coord.z);
	}
	result /= float(SHADOWMAP_PCF_TAP_COUNT);
	return result * 0.5 + 0.5;
}
float shadow_pointlight_pcf(vec3 light)
{
	float distance = length(light);
	vec3 c1 = cross(light, vec3(0.0, 0.0, 1.0));
	vec3 c2 = cross(light, vec3(0.0, 1.0, 0.0));
	vec3 dx = length(c1) > length(c2) ? normalize(c1) : normalize(c2);
	vec3 dy = normalize(cross(light, dx));
	float radius = 2.0 * uLightSize * distance;
	dx *= radius;
	dy *= radius;
	float result = 0.0;
	for (int i = 0; i < SHADOWMAP_PCF_TAP_COUNT; i++)
	{
		float compare = texture(uShadowMapCube, light + dx * poissonDisk[i].x + dy * poissonDisk[i].y).r;
		result += step(0.0, compare - distance);
	}
	result /= float(SHADOWMAP_PCF_TAP_COUNT);
	return result * 0.5 + 0.5;
}
float shadow_directionallight_pcf(vec4 coord[4])
{
	int cascade;
	if (gl_FragCoord.z < uCascadeFarPlane.x) cascade = 0;
	else if (gl_FragCoord.z < uCascadeFarPlane.y) cascade = 1;
	else if (gl_FragCoord.z < uCascadeFarPlane.z) cascade = 2;
	else cascade = 3;
	vec2 lightSize = uLightSizeCorrection[cascade] * uLightSize;
	vec3 coordinate = coord[cascade].xyz / coord[cascade].w;
	float layer = float(cascade);
	float result = 0.0;
	for (int i = 0; i < SHADOWMAP_PCF_TAP_COUNT; i++)
	{
		float compare = texture(uShadowMapArray, vec3(coordinate.xy + poissonDisk[i] * lightSize, layer)).r;
		result += step(0.0, compare - coordinate.z);
	}
	result /= float(SHADOWMAP_PCF_TAP_COUNT);
	return result * 0.5 + 0.5;
}
vec4 common_lightshadow(vec3 pos, vec4 coord[4])
{
	float intensity = 1.0;
	vec3 lightDir = -uLightDir.xyz;
	if (uLightPos.w != 0.0)
	{
		vec3 direction = uLightPos.xyz - pos;
		intensity = max(1.0 - length(direction) / uLightColor.a, 0.0);
		lightDir = normalize(direction);
		if (uLightDir.w > 0.0)
		{
			float spotFactor = dot(lightDir, -uLightDir.xyz);
			intensity *= max(spotFactor - uLightDir.w, 0.0) / (1.0 - uLightDir.w);
			intensity *= shadow_spotlight_pcf(coord[0].xyz / coord[0].w);
		}
		else intensity *= shadow_pointlight_pcf(pos - uLightPos.xyz);
	}
	else intensity *= shadow_directionallight_pcf(coord);
	return vec4(lightDir, intensity * intensity);
}
#pragma DECLARE_END

/**
* PBR_MR 的 BRDF 方程
* @param albedo 基础颜色
* @param V 视图方向单位向量
* @param N 法向单位向量
* @param L 光源方向单位向量
* @return 反射颜色
*/
#pragma DECLARE_BEGIN(common_brdf, FRAGMENT)
uniform float uMetalness;
uniform float uRoughness;
vec3 common_brdf(vec3 albedo, vec3 V, vec3 N, vec3 L)
{
	vec3 H = normalize(L + V);
	float dotNH = max(dot(N, H), 0.0);
	float dotLH = max(dot(L, H), 0.0);
	float roughness = clamp(uRoughness, 0.04, 1.0);
	vec3 Kd = albedo * (1.0 - uMetalness);
	vec3 F0 = mix(vec3(0.04), albedo, uMetalness);

	float alpha = roughness * roughness;
	float denom = dotNH * dotNH * (alpha - 1.0) + 1.0;
	float ndf = 0.31830988618 * alpha / (denom * denom);
	vec3 fresnel = F0 + (1.0 - F0) * exp2(-(5.55473 * dotLH + 6.98316) * dotLH);
	vec3 diffuse = 0.31830988618 * Kd;
	vec3 specular = fresnel * ndf / 4.0;
	return diffuse + specular;
}
#pragma DECLARE_END

/**
* PBR_IBL 实现
* @param albedo 基础颜色
* @param V 视图方向单位向量
* @param N 法向单位向量
* @return 反射颜色
*/
#pragma DECLARE_BEGIN(common_ibl, FRAGMENT, ENABLE_IBL)
uniform float uMetalness;
uniform float uRoughness;
uniform samplerCube uIrradianceMap;
uniform samplerCube uEnvironmentMap;
uniform sampler2D uBRDFIntegrationMap;
vec3 common_ibl(vec3 albedo, vec3 V, vec3 N)
{
	const float mipmapCount = 5.0;
	float dotNV = max(dot(N, V), 0.0);
	float roughness = clamp(uRoughness, 0.04, 1.0);
	vec3 Kd = albedo * (1.0 - uMetalness);
	vec3 F0 = mix(vec3(0.04), albedo, uMetalness);
	vec3 Rf = reflect(-V, N);

	vec2 envBRDF = texture(uBRDFIntegrationMap, vec2(dotNV, roughness)).xy;
	vec3 irradiance = texture(uIrradianceMap, N).rgb;
	vec3 reflection = textureLod(uEnvironmentMap, Rf, roughness * mipmapCount).rgb;
	vec3 fresnel = F0 + (max(vec3(1.0 - roughness), F0) - F0) * exp2(-(5.55473 * dotNV + 6.98316) * dotNV);
	vec3 diffuse = Kd * irradiance * (1.0 - fresnel);
	vec3 specular = reflection * (fresnel * envBRDF.x + envBRDF.y);
	return diffuse + specular;
}
#pragma DECLARE_END

/**
* 折射计算
* @param reflection 反射颜色
* @param V 视图方向单位向量
* @param N 法向单位向量
* @return 最终颜色
*/
#pragma DECLARE_BEGIN(common_refraction, FRAGMENT, ENABLE_REFRACTION)
uniform float uIOR;
uniform float uRoughness;
uniform samplerCube uEnvironmentMap;
vec3 common_refraction(vec3 reflection, vec3 V, vec3 N)
{
	const float mipmapCount = 5.0;
	const float F0 = 0.04;
	float dotNV = max(dot(N, V), 0.0);
	float fresnel = F0 + (1.0 - F0) * exp2(-(5.55473 * dotNV + 6.98316) * dotNV);
	vec3 refractDir = refract(-V, N, 1.0 / uIOR);
	if (length(refractDir) < 0.001)
	{
		refractDir = reflect(-V, N);
	}
	vec3 transmission = textureLod(uEnvironmentMap, refractDir, uRoughness * mipmapCount).rgb;
	return mix(transmission, reflection, fresnel);
}
#pragma DECLARE_END

/**
* 雾效计算
* @param color 源颜色值
* @param pos 视图坐标系下的坐标
* @return 叠加雾效后的颜色
*/
#pragma DECLARE_BEGIN(common_fog, FRAGMENT, ENABLE_FOG)
uniform vec2 uFogRange;
uniform vec4 uFogColor;
vec4 common_fog(vec4 color, vec3 pos)
{
	float fogDensity = clamp((length(pos) - uFogRange.x) / (uFogRange.y - uFogRange.x), 0.0, 1.0);
	vec4 blend = mix(color, uFogColor, fogDensity);
	return vec4(blend.rgb, color.a);
}
#pragma DECLARE_END

/**
* ACES tone mapping
* @param color 转换前的颜色
* @return 转换后的颜色
*/
#pragma DECLARE_BEGIN(common_tonemapping, FRAGMENT， ENABLE_TONEMAPPING)
vec4 common_tonemapping(vec4 color)
{
	const float A = 2.51;
	const float B = 0.03;
	const float C = 2.43;
	const float D = 0.59;
	const float E = 0.14;
	vec3 src = color.rgb;
	return vec4((src * (A * src + B)) / (src * (C * src + D) + E), color.a);
}
#pragma DECLARE_END